<?php
/**
 * Copyright (c) 2008, Till Klampaeckel
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 *  * Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright notice, this
 *    list of conditions and the following disclaimer in the documentation and/or
 *    other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * PHP Version 5
 *
 * @category Services
 * @package  Services_Plazes
 * @author   Till Klampaeckel <till@php.net>
 * @license  http://www.opensource.org/licenses/bsd-license.php The BSD License
 * @version  CVS: $Id$
 * @link     http://code.google.com/p/servicesplazes/
 */

/**
 * Services_Plazes_Adapter_Plazes_Exception
 */
require_once 'Services/Plazes/Adapter/Plazes/Exception.php';

/**
 * A class to interface the API of plazes.com.
 *
 * @category Services
 * @package  Services_Plazes
 * @author   Till Klampaeckel <till@php.net>
 * @license  http://www.opensource.org/licenses/bsd-license.php The BSD License
 * @version  Release: @package_version@
 * @link     http://code.google.com/p/servicesplazes/
 */
final class Services_Plazes_Adapter_Plazes extends Services_Plazes
{
    private $allowedCategories = array('office', 'home', 'restaurant', 'airport',
        'railway_station', 'other', 'hotel', 'conference', 'university', 'bar',
        'coffee_shop', 'club', 'museum', 'theater', 'movie_theater', 'shop', 
        'stadium', 'landmark');

    /**
     * __construct
     */
    private function __construct()
    {
    }
    
    /**
     * factory
     *
     * Used to initialize Users adapter.
     *
     * @param array $params Params passed in from Services_Plazes.
     *
     * @return Services_Plazes_Adapter_Users
     * @uses   Services_Plazes::setParams()
     */
    static function factory($params)
    {
        $plazes = new Services_Plazes_Adapter_Plazes;
        $plazes->setParams($params);
        
        return $plazes;
    }
    
    /**
     * getPlazeCategories
     *
     * Returns all supported categories, which are hardcoded into the class.
     *
     * This is useful if you are creating an interface and/or need to localize the
     * names of the available categories.
     *
     * @return array
     * @uses   self::$allowedCategories
     */
    public function getPlazeCategories()
    {
        return $this->allowedCategories;
    }
    
    /**
     * getPlaze
     *
     * Implements self::getPlazeInfo(), self::getPlazeComments() and
     * self::getPlazePictures(). This feature is not available through the
     * regular API, which is why we issue three requests and combine all
     * information.
     *
     * @param int $id The ID of the plaze.
     *
     * @return array
     * @uses self::getPlazeInfo()
     * @uses self::getPlazeComments()
     * @uses self::getPlazePictures()
     */
    public function getPlaze($id)
    {
        throw new Services_Plazes_Adapter_Plazes_Exception(
            'Not yet implemented.',
            Services_Plazes::ERR_NOT_IMPLEMENTED
        );
    }
    
    /**
     * getPlazeInfo
     *
     * Retrieves all info about a plaze.
     *
     * @param int $id The ID of the plaze.
     *
     * @return array
     * @throws Services_Plazes_Adapter_Plazes_Exception In case the request fails.
     */
    public function getPlazeInfo($id)
    {
        $url = $this->endpoint . '/plazes/' . $id . '.xml';
        try {
            $response = $this->makeRequest($url, 'GET');
        } catch (Services_Plazes_Adapter_Exception $e) {
            throw new Services_Plazes_Adapter_Plazes_Exception(
                $e->getMessage(),
                $e->getCode()
            );
        }
        return $this->_parseResponse($response);
    }
    
    /**
     * getPlazePictures
     *
     * Retrieves all pictures of a plaze.
     *
     * @param int $id The ID of the plaze.
     *
     * @return array
     * @throws Services_Plazes_Adapter_Plazes_Exception In case the request fails.
     */
    public function getPlazePictures($id)
    {
        $url = $this->endpoint . '/plazes/' . $id . '/pictures.xml';
        try {
            $response = $this->makeRequest($url, 'GET');
        } catch (Services_Plazes_Adapter_Exception $e) {
            throw new Services_Plazes_Adapter_Plazes_Exception(
                $e->getMessage(),
                $e->getCode()
            );
        }
        return $this->_parseResponse($response);
    }
    
    /**
     * getPlazeComments
     *
     * Retrieves all comments on a plaze.
     *
     * @param int $id The ID of the plaze.
     *
     * @return array
     * @throws Services_Plazes_Adapter_Plazes_Exception In case the request fails.
     */
    public function getPlazeComments($id)
    {
        $url = $this->endpoint . '/plazes/' . $id . '/comments.xml';
        try {
            $response = $this->makeRequest($url, 'GET');
        } catch (Services_Plazes_Adapter_Exception $e) {
            throw new Services_Plazes_Adapter_Plazes_Exception(
                $e->getMessage(),
                $e->getCode()
            );
        }
        return $this->_parseResponse($response);
    }
    
    /**
     * createPlaze
     *
     * Create a new pla[c,z]e. name, city and country are the absolute minimum.
     *
     * @param array $params Properties/parameters of the newplaze.
     *
     * @return array
     * @throws Services_Plazes_Adapter_Exception In case the request fails.
     * @todo   Return plaze ID.
     */
    public function createPlaze($params)
    {
        if (!isset($params['name'])
            || !isset($params['city'])
            || !isset($params['country'])) {
            throw new Services_Plazes_Adapter_Plazes_Exception(
                'Missing required parameter name, city or country.',
                Services_Plazes::ERR_MISSING_PARAM
            );
        }
        $xml = '<plaze>';
        foreach ($params as $key=>$value) {
            $key  = strtolower($key);
            $xml .= '<' . $key . '>' . $value . '</' . $key . '>';
        }
        $xml .= '</plaze>';
        
        $url = $this->endpoint . '/plazes.xml';
        
        try {
            $response = $this->makeRequest($url, 'POST', $xml);
        } catch (Services_Plazes_Adapter_Exception $e) {
            $msg  = 'Could not create new plaze: ' . $e->getMessage();
            $msg .= ' (' . $e->getCode() . ')';
            throw new Services_Plazes_Adapter_Plazes_Exception(
                $msg,
                Services_Plazes::ERR_CREATE
            );
        }
        return $this->_parseResponse($response);
    }
    
    /**
     * updatePlaze
     *
     * Updates information on a plaze. Only supplied info is overwritten.
     *
     * @param int   $id     The ID of the plaze.
     * @param array $params Properties of the plaze.
     *
     * @return boolean
     * @throws Services_Plazes_Adapter_Plazes_Exception If the update fails.
     */
    public function updatePlaze($id, $params)
    {
        $url = $this->endpoint . '/plazes/' . $id . '.xml';
        
        $xml = '<plaze>';
        foreach ($params as $key=>$value) {
            $key = strtolower($key);
            $xml = '<' . $key . '>' . $value . '</' . $key . '>';
        }
        $xml .= '</plaze>';
        
        try {
            $this->makeRequest($url, 'PUT', $xml);
        } catch (Services_Plazes_Adapter_Exception $e) {
            throw new Services_Plazes_Adapter_Plazes_Exception(
                $e->getMessage(),
                $e->getCode()
            );
        }
        return true;
    }
    
    /**
     * getPlazes
     * 
     * Get plazes from plazes.com.
     *
     * @param string $query       The search query.
     * @param string $mac_address The mac address.
     *
     * @return array
     */
    public function getPlazes($query = null, $mac_address = null)
    {
        $url = $this->endpoint . '/plazes.xml';
        if ($query !== null) {
            $url .= '?q=' . urlencode($query);
        }
        if ($mac_address !== null) {
            if ($query === null) {
                $url .= '?';
            } else {
                $url .= '&';
            }
            $url .= 'mac_address=' . urlencode($mac_address);
        }
        $response = $this->makeRequest($url, 'GET');
        return $this->_parseResponse($response);
    }

    /**
     * _parseResponse
     *
     * @param string $response The response received from the plazes API.
     *
     * @return array
     */
    private function _parseResponse($response)
    {
        $response = trim($response);
        
        $simpleXml = simplexml_load_string($response);
        if (count($simpleXml) > 0) {
            return (array) $simpleXml;
        }

        $response = (array) $simpleXml;
        if (is_array($response) && count($response) == 1) {

            $response[0] = trim($response[0]);
            if (empty($response[0])) {
                return array();
            }
        }
        return $response;
    }
}
?>
